package lion.dev.image;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import org.apache.commons.io.FilenameUtils;

/**
 *
 * 这是一个提供图片处理的简单的类，提供了缩放，旋转，水印，压缩，裁切，清晰，模糊等功能，
 * 这只是争对Gif与其他常见类型做了处理，如果想要使用更加强大的功能，请直接使用
 * com.jhlabs.image下面的filter，在maven上面可以通过com.jhlabs找到，这些滤镜提供了大量的惊人的特效，
 * 对于图片的编码，使用Jimi-pro来完成，其提供的大量编码解码器可以支持绝大多数图片的编码工作
 * 注：ImageIO.write会丢失元数据信息，导致图片失真
 *
 * @author helin
 * @email hl_0074@sina.com
 * @date 2016-07-12
 *
 */
public class ImageJ {

	private String type;
	private IImageHandler handler;

	private ImageJ(IImageHandler handler, String type) {
		this.handler = handler;
		this.type = type;
	}

	private static Map<String, Class<? extends IImageHandler>> handlers = new HashMap<>();

	public ImageJ(BufferedImage image) {
		this(image, "JPEG");
	}

	public ImageJ(BufferedImage image, String type) {
		this.handler = getHandler(type);
		this.handler.read(image);
		this.type = type;
	}

	public ImageJ(InputStream src, String type) throws IOException {

		this.handler = getHandler(type);
		this.handler.read(src);
		this.type = type;
	}

	public ImageJ(File src) throws IOException {
		this(new FileInputStream(src), FilenameUtils.getExtension(src.getName()));
	}

	/**
	 * 压缩图像
	 *
	 * 对于BMP格式的图像的压缩类型： 自上而下，原点在左上角。如果是正数，则图像是自下而上的，原点在左下角
	 * 自底向上的bitmap的压缩类型，（自顶向下的bitmap不能被压缩）。
	 *
	 * @param quality
	 * @return
	 *
	 * 		JPG可以
	 *
	 */
	public ImageJ compress(float quality) {

		IImageHandler handler = this.handler.compress(quality, type);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 限制图片最大宽度或高度
	 */
	public ImageJ limit(int maxwidth, int maxheight) {

		IImageHandler handler = this.handler.limit(maxwidth, maxheight);

		return new ImageJ(handler, this.type);
	}

	/**
	 * 改变图像大尺寸
	 *
	 * @param width
	 *            新宽度
	 * @param height
	 *            新高度
	 * @param scale
	 *            是否约束比例
	 * @return ImageUtil
	 */
	public ImageJ resize(int width, int height) {

		IImageHandler handler = this.handler.resize(width, height);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 按宽度缩放，约束高度比例
	 *
	 * @param width
	 * @return
	 */
	public ImageJ resizeWidth(int width) {

		IImageHandler handler = this.handler.resizeWidth(width);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 按高度缩放，约束宽度比例
	 *
	 * @param height
	 * @return
	 */
	public ImageJ resizeHeight(int height) {

		IImageHandler handler = this.handler.resizeHeight(height);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 按比例缩放宽度和高度
	 *
	 * @param val
	 * @return
	 */
	public ImageJ resizeScale(float percent) {

		IImageHandler handler = this.handler.resizeScale(percent);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 旋转一个图片
	 *
	 * @param rotation
	 * @return
	 */
	public ImageJ rotate(Rotation rotation) {

		IImageHandler handler = this.handler.rotate(rotation);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 获取图片局部
	 *
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @return
	 */
	public ImageJ crop(int x, int y, int width, int height) {

		IImageHandler handler = this.handler.crop(x, y, width, height);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 增加水印，设置水印的x,y坐标
	 *
	 * @param watermark
	 * @param x
	 * @param y
	 * @param opacity
	 * @return
	 */
	public ImageJ watermark(BufferedImage watermark, int x, int y, float opacity) {

		IImageHandler handler = this.handler.watermark(watermark, x, y, opacity);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 增加水印，可选左上，右上，左下，右下，居中四个方向
	 *
	 * @param watermark
	 * @param directoin
	 * @param opacity
	 * @return
	 */
	public ImageJ watermark(BufferedImage watermark, Directoin directoin, float opacity) {

		IImageHandler handler = this.handler.watermark(watermark, directoin, opacity);
		return new ImageJ(handler, this.type);
	}

	public ImageJ sharpen(int times) {

		IImageHandler handler = this.handler.sharpen(times);
		return new ImageJ(handler, this.type);
	}

	/**
	 * 输出图像
	 *
	 * @param os
	 * @throws IOException
	 */
	public void write(OutputStream os) throws IOException {

		this.handler.write(os, this.type);
		os.flush();
	}

	public BufferedImage getImage() {

		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			this.write(baos);
			return ImageIO.read(new ByteArrayInputStream(baos.toByteArray()));
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private IImageHandler getHandler(String type) {

		Class<? extends IImageHandler> clazz = handlers.get(type.toLowerCase());
		if (clazz == null) {
			clazz = DefaultImageHandler.class;
		}
		try {
			IImageHandler handler = clazz.newInstance();
			return handler;
		} catch (InstantiationException | IllegalAccessException e) {
			return new DefaultImageHandler();
		}
	}

	public static void registHandler(String type, Class<? extends IImageHandler> clazz) {

		handlers.put(type, clazz);
	}

	static {
		handlers.put("gif", GifHandler.class);
		handlers.put("ico", ICOHandler.class);
	}
}
